home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / ELECTRON / PCB_DESI / 1540.ZIP / PCBCA110.ZIP / IO.C < prev    next >
C/C++ Source or Header  |  1990-11-18  |  29KB  |  1,031 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #ifndef VMS
  6. #include <malloc.h>
  7. #endif
  8.  
  9. #include <ctype.h>
  10. #include "cell.h"
  11.  
  12. extern int Nrows, Ncols; /* board dimensions */
  13.  
  14. extern int InitBoardDone; /* sanity check */
  15. extern int SortConnects; /* 0 = don't sort, 1 = sort */
  16.  
  17. /* memory usage */
  18. extern unsigned long Ltotal; /* for board */
  19. extern unsigned long Itotal; /* for dist */
  20. extern unsigned long Ctotal; /* for dir */
  21.  
  22. /*
  23. ** the following types of input lines are legal (spaces and tabs can separate
  24. ** tokens, and case is not significant):
  25. **
  26. **  1) a blank line (ignored)
  27. **  2) ';' followed by anything (ignored)
  28. **     use semicolon to insert comments.
  29. **  3) DIMENSION (row,column)
  30. **     this defines the number of rows and columns on the board, and must be
  31. **     given before any of the lines below. note that the user sees the board
  32. **     coordinate space as being 1-based, but internally it is 0-based.
  33. **  4) HOLE (row,column)
  34. **     this defines a hole location.
  35. **  5) CONNECT thing AND thing
  36. **     this declares that two holes are to be electrically connected. a thing
  37. **     can be (row,column), or name1.name2, where name1 is the name of a
  38. **     CHIPAT-defined chip, and name2 is the name of one of its pins, or a
  39. **     number, giving the pin number of the named chip. you can use "TO" or
  40. **     "=" instead of "AND" if you want.
  41. **  6) PRIORITY CONNECT thing AND thing
  42. **     same as above, except the order of connections will be preserved. the
  43. **     autorouter is free to reorder the non-PRIORITY CONNECTs, and in fact
  44. **     reorders them shortest first. if there are PRIORITY CONNECTs, they will
  45. **     all be routed before non-PRIORITY CONNECTs.
  46. **  7) INCLUDE filename
  47. **     this causes the input to be temporarily taken from the given filename.
  48. **     when the given filename is completely processed (EOF encountered),
  49. **     control returns to the current file. INCLUDE statements may be nested
  50. **     (they may occur inside the given filename). complete and partial
  51. **     pathnames can be used (C:\TTL.INC, ..\TTL.INC, \TTL.INC, FOO\TTL.INC).
  52. **  8) CHIP TYPE=type PINS=number HORIZONTAL=number VERTICAL=number
  53. **     this declares a chip type, which can be used to place chips on the
  54. **     board (see CHIPAT, below), but does not itself place anything on the
  55. **     board. TYPE gives the name that will be used in later CHIPAT
  56. **     statements. PINS declares the number of pins. HORIZONTAL gives the
  57. **     number of 50-mil units separating adjacent pins (along the long side of
  58. **     the chip). and VERTICAL gives the number of 50-mil units separating
  59. **     pins across from each other (across the skinny width of the chip).
  60. **     standard values for HORIZONTAL and VERTICAL are 2 and 6, respectively.
  61. **     all CHIP type names must be unique.
  62. **  9) number=name
  63. **     this declares a pin name for the chip that is currently being defined.
  64. **     this statement must follow a CHIP statement. pins not defined will have
  65. **     no name, but you can still refer to them by number. each pin on a chip
  66. **     can be named at most once.
  67. ** 10) name=number
  68. **     same as above.
  69. ** 11) CHIPAT (row,column) NAME=name TYPE=type ORIENTATION=orientation
  70. **     this defines an instance of a chip, and places the appropriate holes on
  71. **     the board. (row,column) is the location of pin 1. NAME defines the name
  72. **     to be used in following CONNECT statements. TYPE declares the
  73. **     CHIPAT-defined type of the chip. ORIENTATION can have the values
  74. **     NORMAL, UP, DOWN, and UPSIDEDOWN. all CHIPAT names must be unique.
  75. **
  76. **      NORMAL           UP           DOWN        UPSIDEDOWN
  77. **
  78. **       6 5 4          +---+         +---+          3 2 1
  79. **     +-*-*-*-+      4 *   * 3     1 * | * 6      +-*-*-*-+
  80. **     |  ->   |      5 * ^ * 2     2 * v * 5      |   <-  |
  81. **     +-*-*-*-+      6 * | * 1     3 *   * 4      +-*-*-*-+
  82. **       1 2 3          +---+         +---+          4 5 6
  83. **
  84. **     usually the highest-numbered pin (pin N) is Vcc (power) and the pin
  85. **     farthest from it (pin N/2) is GND (ground).
  86. */
  87.  
  88. /* chip orientations (rotations) */
  89. #define ORIENT_NORMAL        1
  90. #define ORIENT_UP        2
  91. #define ORIENT_DOWN        3
  92. #define ORIENT_UPSIDEDOWN    4
  93.  
  94. /* input token types */
  95. #define TOK_EOF        1    /* end of file, no more tokens        */
  96. #define TOK_NEWLINE    2    /* end of line                */
  97. #define TOK_NUMBER    3    /* number (digits)            */
  98. #define TOK_HOLE    4    /* "HOLE"                */
  99. #define TOK_ROWCOLUMN    5    /* "(row,column)"            */
  100. #define TOK_CONNECT    6    /* "CONNECT"                */
  101. #define TOK_EQUAL    7    /* "="                    */
  102. #define TOK_AND        8    /* "AND"                */
  103. #define TOK_ALPHANUM    9    /* name (letters, digits, ':','.','\')    */
  104. #define TOK_CHIP    10    /* "CHIP"                */
  105. #define TOK_NAME    11    /* "NAME"                */
  106. #define TOK_PINS    12    /* "PINS"                */
  107. #define TOK_HORIZONTAL    13    /* "HORIZONTAL"                */
  108. #define TOK_VERTICAL    14    /* "VERTICAL"                */
  109. #define TOK_INCLUDE    15    /* "INCLUDE"                */
  110. #define TOK_CHIPAT    16    /* "CHIPAT"                */
  111. #define TOK_TYPE    17    /* "TYPE"                */
  112. #define TOK_ORIENTATION    18    /* "ORIENTATION"            */
  113. #define TOK_NORMAL    19    /* "NORMAL"                */
  114. #define TOK_UP        20    /* "UP"                    */
  115. #define TOK_DOWN    21    /* "DOWN"                */
  116. #define TOK_UPSIDEDOWN    22    /* "UPSIDEDOWN"                */
  117. #define TOK_DIMENSION    23    /* "DIMENSION"                */
  118. #define TOK_PRIORITY    24    /* "PRIORITY"                */
  119. #define TOK_TO        25    /* "TO"                    */
  120.  
  121. struct reserved { /* reserved word input tokens */
  122.     char *tokenname;
  123.     int tokenvalue;
  124.     };
  125.  
  126. static struct reserved tokenmatch[] = { /* reserved word table */
  127.   { "HOLE",       TOK_HOLE       },  { "CONNECT",     TOK_CONNECT     },
  128.   { "AND",        TOK_AND        },  { "CHIP",        TOK_CHIP        },
  129.   { "NAME",       TOK_NAME       },  { "PINS",        TOK_PINS        },
  130.   { "HORIZONTAL", TOK_HORIZONTAL },  { "VERTICAL",    TOK_VERTICAL    },
  131.   { "INCLUDE",    TOK_INCLUDE    },  { "CHIPAT",      TOK_CHIPAT      },
  132.   { "TYPE",       TOK_TYPE       },  { "ORIENTATION", TOK_ORIENTATION },
  133.   { "NORMAL",     TOK_NORMAL     },  { "UP",          TOK_UP          },
  134.   { "DOWN",       TOK_DOWN       },  { "UPSIDEDOWN",  TOK_UPSIDEDOWN  },
  135.   { "DIMENSION",  TOK_DIMENSION  },  { "PRIORITY",    TOK_PRIORITY    },
  136.   { "TO",         TOK_TO         }
  137.  };
  138.  
  139. #define MAXTOK    80    /* maximum token length (including null) */
  140.  
  141. static int numres = sizeof(tokenmatch) / sizeof(tokenmatch[0]);
  142. static char token[MAXTOK]; /* the current token is formed here */
  143.  
  144. struct pinassign { /* for assigning names to pins */
  145.     int            index;
  146.     char far        *name;
  147.     struct pinassign far    *next;
  148.     };
  149.  
  150. struct template { /* for "CHIP" declarations */
  151.     char far        *type;
  152.     int            pins;
  153.     int            horizontal;
  154.     int            vertical;
  155.     struct pinassign far    *pinlist;
  156.     struct template far    *next;
  157.     };
  158.  
  159. struct instance { /* for "CHIPAT" definitions */
  160.     int            row;
  161.     int            column;
  162.     char far        *name;
  163.     struct template far    *type;
  164.     int            orientation;
  165.     struct instance far    *next;
  166.     };
  167.  
  168. static struct template far *chip = NULL; /* list of CHIPs */
  169. static struct instance far *chipat = NULL; /* list of CHIPATs */
  170.  
  171. extern void InitBoard( void );
  172. extern long GetCell( int, int, int );
  173. extern void SetCell( int, int, int, long );
  174. extern void InitWork( void );
  175. extern void SetWork( int, int, char far *, int, int, char far *, int );
  176. extern void SortWork( void );
  177. extern void Nomem( void );
  178.  
  179. int Initialize( char *, int );
  180. static int initfile( FILE *, char * );
  181. static void initchip( struct instance far *, char *, int );
  182. static void locate( char *, int *, int *, char *, int );
  183. static int gettoken( FILE *, char *, int );
  184. static char far *fcopy( char * );
  185. static int same( char far *, char far * );
  186. void Report( FILE * );
  187.  
  188. int Initialize ( file, echo ) /* get hole coordinates and connections */
  189.     char *file;
  190.     int echo;
  191.     {
  192.     FILE *fp;
  193.     int tot;
  194.  
  195.     if (echo)
  196.         printf( "Enter Initialize()\n" );
  197.     if (!(fp = fopen( file, "r" ))) {
  198.         fprintf( stderr, "can't open %s\n", file );
  199.         exit( -1 );
  200.         }
  201.     InitWork(); /* clear work list */
  202.     tot = initfile( fp, file ); /* read input file(s) */
  203.     if (SortConnects)
  204.         SortWork(); /* arrange to do shortest ones first */
  205.     if (echo) {
  206.         printf( "  %lu bytes used for Board\n", Ltotal );
  207.         printf( "  %lu bytes used for Dist\n", Itotal );
  208.         printf( "  %lu bytes used for Dir\n", Ctotal );
  209.         printf( "Exit Initialize()\n" );
  210.         }
  211.     if (fclose( fp ))
  212.         fprintf( stderr, "error closing %s\n", file );
  213.     return( tot );
  214.     }
  215.  
  216. /* some useful macros (common code sequences) */
  217.  
  218. #define FileLine    { fprintf( stderr, "%s(%d): ", file, line ); }
  219.  
  220. #define GetTok(tok)    ((tok) = gettoken( fp, file, line ))
  221.  
  222. #define SkipRest    { while (GetTok(tok) != TOK_EOF \
  223.                 && tok != TOK_NEWLINE) ; \
  224.             if (tok == TOK_NEWLINE) line++; }
  225.  
  226. #define SkipTokRest    { while (tok != TOK_EOF && tok != TOK_NEWLINE) \
  227.                 GetTok(tok); } \
  228.             if (tok == TOK_NEWLINE) line++; \
  229.             continue;
  230.  
  231. #define CheckInit    { if (!InitBoardDone) { \
  232.                 FileLine; \
  233.                 fprintf( stderr, "need dimensions first\n" ); \
  234.                 SkipRest; \
  235.                 continue; } }
  236.  
  237. static int initfile ( fp, file ) /* read and process input file(s) */
  238.     FILE *fp;
  239.     char *file;
  240.     {
  241.     int tok, r1, c1, r2, c2, i, line;
  242.     char far *p;
  243.     char far *n1;
  244.     char far *n2;
  245.     long cell;
  246.     struct template far *p1;
  247.     struct pinassign far *p2;
  248.     struct pinassign far *p22;
  249.     struct instance far *p3;
  250.     FILE *fnew;
  251.     char *fname;
  252.     int tot = 0;
  253.  
  254.     line = 1;
  255.     while (GetTok(tok) != TOK_EOF) {
  256.         if (tok == TOK_DIMENSION) {
  257.             if (InitBoardDone) { /* can only do it once */
  258.                 FileLine;
  259.                 fprintf( stderr,
  260.                     "redundant dimensions\n" );
  261.                 SkipRest;
  262.                 continue;
  263.                 }
  264.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  265.                 FileLine;
  266.                 fprintf( stderr, "expect (row,column)\n" );
  267.                 SkipTokRest;
  268.                 }
  269.             sscanf( token, "(%d,%d)", &Nrows, &Ncols );
  270.             if (Nrows <= 0 || Ncols <= 0) {
  271.                 FileLine;
  272.                 fprintf( stderr, "dimension error\n" );
  273.                 }
  274.             else /* allocate memory for data structures */
  275.                 InitBoard();
  276.             }
  277.         else if (tok == TOK_HOLE) {
  278.             CheckInit; /* must get dimensions first */
  279.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  280.                 FileLine;
  281.                 fprintf( stderr, "expect (row,column)\n" );
  282.                 SkipTokRest;
  283.                 }
  284.             sscanf( token, "(%d,%d)", &r1, &c1 );
  285.             if (r1 <= 0 || r1 > Nrows || c1 <= 0 || c1 > Ncols) {
  286.                 FileLine;
  287.                 fprintf( stderr, "out of range\n" );
  288.                 }
  289.             else { /* position the hole on the board */
  290.                 /* should check for neighbor holes (error) */
  291.                 SetCell( r1-1, c1-1, TOP, HOLE );
  292.                 SetCell( r1-1, c1-1, BOTTOM, HOLE );
  293.                 }
  294.             }
  295.         else if (tok == TOK_CONNECT) {
  296.             CheckInit; /* must get dimensions first */
  297.             if (GetTok(tok) == TOK_ROWCOLUMN)
  298.                 sscanf( token, "(%d,%d)", &r1, &c1 );
  299.             else if (tok == TOK_ALPHANUM)
  300.                 locate( token, &r1, &c1, file, line );
  301.             else {
  302.                 FileLine;
  303.                 fprintf( stderr,
  304.                     "expect (row,column) or name\n" );
  305.                 SkipTokRest;
  306.                 }
  307.             n1 = fcopy( token );
  308.             if (GetTok(tok) != TOK_EQUAL
  309.                 && tok != TOK_AND && tok != TOK_TO) {
  310.                 FileLine;
  311.                 fprintf( stderr, "expect = or AND or TO\n" );
  312.                 SkipTokRest;
  313.                 }
  314.             if (GetTok(tok) == TOK_ROWCOLUMN)
  315.                 sscanf( token, "(%d,%d)", &r2, &c2 );
  316.             else if (tok == TOK_ALPHANUM)
  317.                 locate( token, &r2, &c2, file, line );
  318.             else {
  319.                 FileLine;
  320.                 fprintf( stderr,
  321.                     "expect (row,column) or name\n" );
  322.                 SkipTokRest;
  323.                 }
  324.             n2 = fcopy( token );
  325.             if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  326.                 || c1 <= 0 || c1 > Ncols
  327.                 || c2 <= 0 || c2 > Ncols) {
  328.                 FileLine;
  329.                 fprintf( stderr, "out of range\n" );
  330.                 _ffree( n1 );
  331.                 _ffree( n2 );
  332.                 }
  333.             else {
  334.                 cell = GetCell( r1-1, c1-1, TOP );
  335.                 if (!(cell & HOLE)) {
  336.                     FileLine;
  337.                     fprintf( stderr, "no source hole\n" );
  338.                     _ffree( n1 );
  339.                     _ffree( n2 );
  340.                     SkipRest;
  341.                     continue;
  342.                     }
  343.                 cell = GetCell( r2-1, c2-1, TOP );
  344.                 if (!(cell & HOLE)) {
  345.                     FileLine;
  346.                     fprintf( stderr, "no target hole\n" );
  347.                     _ffree( n1 );
  348.                     _ffree( n2 );
  349.                     SkipRest;
  350.                     continue;
  351.                     }
  352.                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 0 );
  353.                 tot++;
  354.                 }
  355.             }
  356.         else if (tok == TOK_PRIORITY) {
  357.             CheckInit; /* must get dimensions first */
  358.             if (GetTok(tok) != TOK_CONNECT) {
  359.                 FileLine;
  360.                 fprintf( stderr, "expect CONNECT\n" );
  361.                 SkipTokRest;
  362.                 }
  363.             if (GetTok(tok) == TOK_ROWCOLUMN)
  364.                 sscanf( token, "(%d,%d)", &r1, &c1 );
  365.             else if (tok == TOK_ALPHANUM)
  366.                 locate( token, &r1, &c1, file, line );
  367.             else {
  368.                 FileLine;
  369.                 fprintf( stderr,
  370.                     "expect (row,column) or name\n" );
  371.                 SkipTokRest;
  372.                 }
  373.             n1 = fcopy( token );
  374.             if (GetTok(tok) != TOK_EQUAL
  375.                 && tok != TOK_AND && tok != TOK_TO) {
  376.                 FileLine;
  377.                 fprintf( stderr, "expect = or AND or TO\n" );
  378.                 SkipTokRest;
  379.                 }
  380.             if (GetTok(tok) == TOK_ROWCOLUMN)
  381.                 sscanf( token, "(%d,%d)", &r2, &c2 );
  382.             else if (tok == TOK_ALPHANUM)
  383.                 locate( token, &r2, &c2, file, line );
  384.             else {
  385.                 FileLine;
  386.                 fprintf( stderr,
  387.                     "expect (row,column) or name\n" );
  388.                 SkipTokRest;
  389.                 }
  390.             n2 = fcopy( token );
  391.             if (r1 <= 0 || r1 > Nrows || r2 <= 0 || r2 > Nrows
  392.                 || c1 <= 0 || c1 > Ncols
  393.                 || c2 <= 0 || c2 > Ncols) {
  394.                 FileLine;
  395.                 fprintf( stderr, "out of range\n" );
  396.                 _ffree( n1 );
  397.                 _ffree( n2 );
  398.                 }
  399.             else {
  400.                 cell = GetCell( r1-1, c1-1, TOP );
  401.                 if (!(cell & HOLE)) {
  402.                     FileLine;
  403.                     fprintf( stderr, "no source hole\n" );
  404.                     _ffree( n1 );
  405.                     _ffree( n2 );
  406.                     SkipRest;
  407.                     continue;
  408.                     }
  409.                 cell = GetCell( r2-1, c2-1, TOP );
  410.                 if (!(cell & HOLE)) {
  411.                     FileLine;
  412.                     fprintf( stderr, "no target hole\n" );
  413.                     _ffree( n1 );
  414.                     _ffree( n2 );
  415.                     SkipRest;
  416.                     continue;
  417.                     }
  418.                 SetWork( r1-1, c1-1, n1, r2-1, c2-1, n2, 1 );
  419.                 tot++;
  420.                 }
  421.             }
  422.         else if (tok == TOK_INCLUDE) {
  423.             CheckInit; /* must get dimensions first */
  424.             if (GetTok(tok) != TOK_ALPHANUM) {
  425.                 FileLine;
  426.                 fprintf( stderr,
  427.                     "expect file name for INCLUDE\n" );
  428.                 SkipTokRest;
  429.                 }
  430.             if (!(fnew = fopen( token, "r" ))) {
  431.                 FileLine;
  432.                 fprintf( stderr,
  433.                     "can't open INCLUDE file %s\n",
  434.                     token );
  435.                 SkipRest;
  436.                 continue;
  437.                 }
  438. #ifdef VMS
  439.             if (!(fname = _fmalloc( strlen( token )+1 )))
  440.                 Nomem();
  441.             strcpy( fname, token );
  442. #else
  443.             if (!(fname = strdup( token )))
  444.                 Nomem();
  445. #endif
  446.             if (GetTok(tok) != TOK_EOF
  447.                 && tok != TOK_NEWLINE) {
  448.                 FileLine;
  449.                 fprintf( stderr,
  450.                     "extra chars on INCLUDE line\n" );
  451.                 SkipRest;
  452.                 }
  453.             if (tok == TOK_NEWLINE)
  454.                 line++;
  455.             tot += initfile( fnew, fname ); /* recurse */
  456.             if (fclose( fnew )) {
  457.                 FileLine;
  458.                 fprintf( stderr,
  459.                     "error closing INCLUDE file\n" );
  460.                 }
  461.             free( fname );
  462.             continue; /* already ate the NEWLINE, if any */
  463.             }
  464.         else if (tok == TOK_CHIP) {
  465.             CheckInit; /* must get dimensions first */
  466.             if (GetTok(tok) != TOK_TYPE
  467.                 || GetTok(tok) != TOK_EQUAL
  468.                 || GetTok(tok) != TOK_ALPHANUM) {
  469.                 FileLine;
  470.                 fprintf( stderr, "expect TYPE=type\n" );
  471.                 SkipTokRest;
  472.                 }
  473.             if (!(p1 = (struct template far *)
  474.                 _fmalloc( sizeof(struct template) )))
  475.                 Nomem();
  476.             p1->type = fcopy( token );
  477.             if (GetTok(tok) != TOK_PINS
  478.                 || GetTok(tok) != TOK_EQUAL
  479.                 || GetTok(tok) != TOK_NUMBER) {
  480.                 FileLine;
  481.                 fprintf( stderr, "expect PINS=number\n" );
  482.                 _ffree( p1->type );
  483.                 _ffree( p1 );
  484.                 SkipTokRest;
  485.                 }
  486.             sscanf( token, "%d", &i );
  487.             p1->pins = i;
  488.             if ((p1->pins = i) < 0 || (i & 1)) {
  489.                 FileLine;
  490.                 fprintf( stderr, "PINS negative or odd\n" );
  491.                 }
  492.             if (GetTok(tok) != TOK_HORIZONTAL
  493.                 || GetTok(tok) != TOK_EQUAL
  494.                 || GetTok(tok) != TOK_NUMBER) {
  495.                 FileLine;
  496.                 fprintf( stderr,
  497.                     "expect HORIZONTAL=number\n" );
  498.                 _ffree( p1->type );
  499.                 _ffree( p1 );
  500.                 SkipTokRest;
  501.                 }
  502.             sscanf( token, "%d", &i );
  503.             if ((p1->horizontal = i) <= 0) {
  504.                 FileLine;
  505.                 fprintf( stderr, "HORIZONTAL nonpositive\n" );
  506.                 }
  507.             if (GetTok(tok) != TOK_VERTICAL
  508.                 || GetTok(tok) != TOK_EQUAL
  509.                 || GetTok(tok) != TOK_NUMBER) {
  510.                 FileLine;
  511.                 fprintf( stderr, "expect VERTICAL=number\n" );
  512.                 _ffree( p1->type );
  513.                 _ffree( p1 );
  514.                 SkipTokRest;
  515.                 }
  516.             sscanf( token, "%d", &i );
  517.             if ((p1->vertical = i) < 0) {
  518.                 FileLine;
  519.                 fprintf( stderr, "VERTICAL nonpositive\n" );
  520.                 }
  521.             p1->pinlist = NULL;
  522.             p1->next = chip;
  523.             chip = p1;
  524.             }
  525.         else if (tok == TOK_NUMBER) {
  526.             CheckInit; /* must get dimensions first */
  527.             if (!chip) {
  528.                 FileLine;
  529.                 fprintf( stderr, "no template\n" );
  530.                 SkipRest;
  531.                 continue;
  532.                 }
  533.             sscanf( token, "%d", &i );
  534.             if (GetTok(tok) != TOK_EQUAL
  535.                 || GetTok(tok) != TOK_ALPHANUM) {
  536.                 FileLine;
  537.                 fprintf( stderr, "expect number=name\n" );
  538.                 SkipTokRest;
  539.                 }
  540.             if (!(p2 = (struct pinassign far *)
  541.                 _fmalloc( sizeof(struct pinassign) )))
  542.                 Nomem();
  543.             p2->name = fcopy( token );
  544.             p2->index = i;
  545.             /* check uniqueness of name and index */
  546.             for (p22 = chip->pinlist; p22; p22 = p22->next)
  547.                 if (p22->index == i
  548.                     || same( p22->name, p )) {
  549.                     FileLine;
  550.                     fprintf( stderr,
  551.                         "warning: repeated pin\n" );
  552.                     break;
  553.                     }
  554.             p2->next = chip->pinlist;
  555.             chip->pinlist = p2;
  556.             }
  557.         else if (tok == TOK_ALPHANUM) {
  558.             CheckInit; /* must get dimensions first */
  559.             if (!chip) {
  560.                 FileLine;
  561.                 fprintf( stderr, "no template\n" );
  562.                 SkipRest;
  563.                 continue;
  564.                 }
  565.             p = fcopy( token );
  566.             if (GetTok(tok) != TOK_EQUAL
  567.                 || GetTok(tok) != TOK_NUMBER) {
  568.                 FileLine;
  569.                 fprintf( stderr, "expect name=number\n" );
  570.                 _ffree( p );
  571.                 SkipTokRest;
  572.                 }
  573.             sscanf( token, "%d", &i );
  574.             if (!(p2 = (struct pinassign far *)
  575.                 _fmalloc( sizeof(struct pinassign) )))
  576.                 Nomem();
  577.             p2->name = p;
  578.             p2->index = i;
  579.             /* check uniqueness of name and index */
  580.             for (p22 = chip->pinlist; p22; p22 = p22->next)
  581.                 if (p22->index == i
  582.                     || same( p22->name, p )) {
  583.                     FileLine;
  584.                     fprintf( stderr,
  585.                         "warning: repeated pin\n" );
  586.                     break;
  587.                     }
  588.             p2->next = chip->pinlist;
  589.             chip->pinlist = p2;
  590.             }
  591.         else if (tok == TOK_CHIPAT) {
  592.             CheckInit; /* must get dimensions first */
  593.             if (GetTok(tok) != TOK_ROWCOLUMN) {
  594.                 FileLine;
  595.                 fprintf( stderr, "expect (row,column)\n" );
  596.                 SkipTokRest;
  597.                 }
  598.             sscanf( token, "(%d,%d)", &r1, &c1 );
  599.             if (GetTok(tok) != TOK_NAME
  600.                 || GetTok(tok) != TOK_EQUAL
  601.                 || GetTok(tok) != TOK_ALPHANUM) {
  602.                 FileLine;
  603.                 fprintf( stderr, "expect NAME=name\n" );
  604.                 SkipTokRest;
  605.                 }
  606.             if (!(p3 = (struct instance far *)
  607.                 _fmalloc( sizeof(struct instance) )))
  608.                 Nomem();
  609.             p3->name = fcopy( token );
  610.             p3->row = r1;
  611.             p3->column = c1;
  612.             if (GetTok(tok) != TOK_TYPE
  613.                 || GetTok(tok) != TOK_EQUAL
  614.                 || GetTok(tok) != TOK_ALPHANUM) {
  615.                 FileLine;
  616.                 fprintf( stderr, "expect TYPE=type\n" );
  617.                 _ffree( p3->name );
  618.                 _ffree( p3 );
  619.                 SkipTokRest;
  620.                 }
  621.             for (p3->type = chip; p3->type;
  622.                 p3->type = p3->type->next)
  623.                 if (same( token, p3->type->type ))
  624.                     break;
  625.             if (!(p3->type)) {
  626.                 FileLine;
  627.                 fprintf( stderr,
  628.                     "couldn't find chip type\n" );
  629.                 _ffree( p3->name );
  630.                 _ffree( p3 );
  631.                 SkipTokRest;
  632.                 }
  633.             if (GetTok(tok) != TOK_ORIENTATION
  634.                 || GetTok(tok) != TOK_EQUAL
  635.                 || (GetTok(tok) != TOK_NORMAL
  636.                 && tok != TOK_UP && tok != TOK_DOWN
  637.                 && tok != TOK_UPSIDEDOWN)) {
  638.                 FileLine;
  639.                 fprintf( stderr,
  640.                     "expect ORIENTATION=orientation\n" );
  641.                 _ffree( p3->name );
  642.                 _ffree( p3 );
  643.                 SkipTokRest;
  644.                 }
  645.             switch (tok) {
  646.             case TOK_NORMAL:
  647.                 p3->orientation = ORIENT_NORMAL;    break;
  648.             case TOK_UP:
  649.                 p3->orientation = ORIENT_UP;        break;
  650.             case TOK_DOWN:
  651.                 p3->orientation = ORIENT_DOWN;        break;
  652.             case TOK_UPSIDEDOWN:
  653.                 p3->orientation = ORIENT_UPSIDEDOWN;    break;
  654.             default:
  655.                 FileLine;
  656.                 fprintf( stderr, "internal error\n" );
  657.                 exit( -1 );
  658.                 break;
  659.                 }
  660.             p3->next = chipat;
  661.             chipat = p3;
  662.             initchip( p3, file, line );
  663.             }
  664.         else if (tok == TOK_NEWLINE) {
  665.             line++;
  666.             continue;
  667.             }
  668.         else { /* something unexpected */
  669.             FileLine;
  670.             fprintf( stderr, "syntax error: unexpected input\n" );
  671.             }
  672.         if (GetTok(tok) != TOK_EOF
  673.             && tok != TOK_NEWLINE) {
  674.             FileLine;
  675.             fprintf( stderr,
  676.                 "syntax error: expected end of line\n" );
  677.             SkipRest;
  678.             }
  679.         else if (tok == TOK_NEWLINE)
  680.             line++;
  681.         }
  682.     return( tot );
  683.     }
  684.  
  685. static void initchip ( p, file, line ) /* init chip definition (make holes) */
  686.     struct instance far *p;
  687.     char *file;
  688.     int line;
  689.     {
  690.     int r, c, pin;
  691.     struct template far *t;
  692.  
  693.     pin = 1;
  694.     r = p->row;
  695.     c = p->column;
  696.     t = p->type;
  697.     /* should check for neighboring holes (warning if so) */
  698.     switch (p->orientation) {
  699.     case ORIENT_NORMAL:
  700.         while (pin <= t->pins / 2) {
  701.             SetCell( r-1, c-1, TOP, HOLE );
  702.             SetCell( r-1, c-1, BOTTOM, HOLE );
  703.             pin++;
  704.             c += t->horizontal;
  705.             }
  706.         c -= t->horizontal;
  707.         r += t->vertical;
  708.         while (pin <= t->pins) {
  709.             SetCell( r-1, c-1, TOP, HOLE );
  710.             SetCell( r-1, c-1, BOTTOM, HOLE );
  711.             pin++;
  712.             c -= t->horizontal;
  713.             }
  714.         break;
  715.     case ORIENT_UP:
  716.         while (pin <= t->pins / 2) {
  717.             SetCell( r-1, c-1, TOP, HOLE );
  718.             SetCell( r-1, c-1, BOTTOM, HOLE );
  719.             pin++;
  720.             r += t->horizontal;
  721.             }
  722.         r -= t->horizontal;
  723.         c -= t->vertical;
  724.         while (pin <= t->pins) {
  725.             SetCell( r-1, c-1, TOP, HOLE );
  726.             SetCell( r-1, c-1, BOTTOM, HOLE );
  727.             pin++;
  728.             r -= t->horizontal;
  729.             }
  730.         break;
  731.     case ORIENT_DOWN:
  732.         while (pin <= t->pins / 2) {
  733.             SetCell( r-1, c-1, TOP, HOLE );
  734.             SetCell( r-1, c-1, BOTTOM, HOLE );
  735.             pin++;
  736.             r -= t->horizontal;
  737.             }
  738.         r += t->horizontal;
  739.         c += t->vertical;
  740.         while (pin <= t->pins) {
  741.             SetCell( r-1, c-1, TOP, HOLE );
  742.             SetCell( r-1, c-1, BOTTOM, HOLE );
  743.             pin++;
  744.             r += t->horizontal;
  745.             }
  746.         break;
  747.     case ORIENT_UPSIDEDOWN:
  748.         while (pin <= t->pins / 2) {
  749.             SetCell( r-1, c-1, TOP, HOLE );
  750.             SetCell( r-1, c-1, BOTTOM, HOLE );
  751.             pin++;
  752.             c -= t->horizontal;
  753.             }
  754.         c += t->horizontal;
  755.         r -= t->vertical;
  756.         while (pin <= t->pins) {
  757.             SetCell( r-1, c-1, TOP, HOLE );
  758.             SetCell( r-1, c-1, BOTTOM, HOLE );
  759.             pin++;
  760.             c += t->horizontal;
  761.             }
  762.         break;
  763.     default:
  764.         FileLine;
  765.         fprintf( stderr, "internal error: unexpected orientation\n" );
  766.         exit( -1 );
  767.         break;
  768.         }
  769.     }
  770.  
  771. static void locate ( p, r, c, file, line )
  772.     /* find location of name1.{name2,number} */
  773.     char *p;
  774.     int *r, *c;
  775.     char *file;
  776.     int line;
  777.     {
  778.     char *q;
  779.     int i;
  780.     struct instance far *s;
  781.     struct pinassign far *t;
  782.  
  783.     if (!(q = strchr( p, '.' ))) {
  784.         FileLine;
  785.         fprintf( stderr, "expect name1.{name2,number}\n" );
  786.         return;
  787.         }
  788.     *q++ = 0; /* separate into two parts & point at second part */
  789.     for (s = chipat; s; s = s->next) /* find proper chip */
  790.         if (same( p, s->name ))
  791.             break;
  792.     if (!s || !(s->type)) {
  793.         FileLine;
  794.         fprintf( stderr, "can't find chip or chip type\n" );
  795.         return;
  796.         }
  797.     if (isdigit( *q )) { /* get pin number */
  798.         i = atoi( q );
  799.         if (i <= 0 || i > s->type->pins) {
  800.             FileLine;
  801.             fprintf( stderr, "pin out of range\n" );
  802.             return;
  803.             }
  804.         }
  805.     else { /* get index of named pin via the template */
  806.         for (t = s->type->pinlist; t; t = t->next)
  807.             if (same( q, t->name ))
  808.                 break;
  809.         if (!t) {
  810.             FileLine;
  811.             fprintf( stderr, "can't find pin\n" );
  812.             return;
  813.             }
  814.         i = t->index;
  815.         }
  816.     *r = s->row;
  817.     *c = s->column;
  818.     switch (s->orientation) {
  819.     case ORIENT_NORMAL:
  820.         if (i <= s->type->pins / 2)
  821.             *c += (i-1) * s->type->horizontal;
  822.         else {
  823.             *r += s->type->vertical;
  824.             *c += (s->type->pins - i) * s->type->horizontal;
  825.             }
  826.         break;
  827.     case ORIENT_UP:
  828.         if (i <= s->type->pins / 2)
  829.             *r += (i-1) * s->type->horizontal;
  830.         else {
  831.             *c -= s->type->vertical;
  832.             *r += (s->type->pins - i) * s->type->horizontal;
  833.             }
  834.         break;
  835.     case ORIENT_DOWN:
  836.         if (i <= s->type->pins / 2)
  837.             *r -= (i-1) * s->type->horizontal;
  838.         else {
  839.             *c += s->type->vertical;
  840.             *r -= (s->type->pins - i) * s->type->horizontal;
  841.             }
  842.         break;
  843.     case ORIENT_UPSIDEDOWN:
  844.         if (i <= s->type->pins / 2)
  845.             *c -= (i-1) * s->type->horizontal;
  846.         else {
  847.             *r -= s->type->vertical;
  848.             *c -= (s->type->pins - i) * s->type->horizontal;
  849.             }
  850.         break;
  851.     default:
  852.         FileLine;
  853.         fprintf( stderr, "internal error: unexpected orientation\n" );
  854.         exit( -1 );
  855.         break;
  856.         }
  857.     *--q = '.'; /* put back the separator */
  858.     }
  859.  
  860. static int gettoken ( fp, file, line )
  861.     /* get next token into token[], return value */
  862.     FILE *fp;
  863.     char *file;
  864.     int line;
  865.     {
  866.     int ch, i;
  867.  
  868.     /* burn whitespace */
  869.     while ((ch = getc( fp )) == ' ' || ch == '\t')
  870.         ;
  871.     if (ch == EOF)
  872.         return( TOK_EOF );
  873.     else if (ch == '\n')
  874.         return( TOK_NEWLINE );
  875.     else if (ch == ';') { /* comment; burn to end of line */
  876.         while ((ch = getc( fp )) != EOF && ch != '\n')
  877.             ;
  878.         return( (ch == '\n') ? TOK_NEWLINE : TOK_EOF );
  879.         }
  880.     else if (ch == '=')
  881.         return( TOK_EQUAL );
  882.     else if (isdigit( ch )) { /* a number; move it to the buffer */
  883.         i = 0;
  884.         do {
  885.             if (i < MAXTOK-1)
  886.                 token[i++] = (char)ch;
  887.             ch = getc( fp );
  888.             } while (isdigit( ch ));
  889.         token[i] = 0;
  890.         if (ch != EOF)
  891.             ungetc( ch, fp );
  892.         return( TOK_NUMBER );
  893.         }
  894.     else if (isalpha( ch ) || ch == '.' || ch == '\\') {
  895.         /* a name; move it to the buffer */
  896.         i = 0;
  897.         do {
  898.             if (i < MAXTOK-1)
  899.                 token[i++] = (char)ch;
  900.             ch = getc( fp );
  901.             } while (isalnum( ch ) || ch == ':' || ch == '.'
  902.                 || ch == '\\');
  903.         token[i] = 0;
  904.         if (ch != EOF)
  905.             ungetc( ch, fp );
  906.         /* try to identify it as a reserved word */
  907.         for (i = 0; i < numres; i++) /* search table */
  908.             if (!stricmp( tokenmatch[i].tokenname, token ))
  909.                 return( tokenmatch[i].tokenvalue );
  910.         /* it's not a reserved word; just return it */
  911. #ifdef VMS
  912.         for (i = 0; i < strlen( token ); i++) /* make uppercase */
  913.             if (token[i] >= 'a' && token[i] <= 'z')
  914.                 token[i] -= ('a'-'A');
  915. #else
  916.         strupr( token );
  917. #endif
  918.         return( TOK_ALPHANUM );
  919.         }
  920.     else if (ch == '(') { /* "(row,column)", move it to the buffer */
  921.         token[0] = (char)ch;
  922.         i = 1;
  923.         while ((ch = getc( fp )) == ' ' || ch == '\t')
  924.             ;
  925.         if (!isdigit( ch )) {
  926.             FileLine;
  927.             fprintf( stderr, "syntax error: expected digit\n" );
  928.             exit( -1 );
  929.             }
  930.         do {
  931.             if (i < MAXTOK-1)
  932.                 token[i++] = (char)ch;
  933.             ch = getc( fp );
  934.             } while (isdigit( ch ));
  935.         while (ch == ' ' || ch == '\t')
  936.             ch = getc( fp );
  937.         if (ch != ',') {
  938.             FileLine;
  939.             fprintf( stderr, "syntax error: expected comma\n" );
  940.             exit( -1 );
  941.             }
  942.         if (i < MAXTOK-1)
  943.             token[i++] = (char)ch;
  944.         while ((ch = getc( fp )) == ' ' || ch == '\t')
  945.             ;
  946.         if (!isdigit( ch )) {
  947.             FileLine;
  948.             fprintf( stderr, "syntax error: expected digit\n" );
  949.             exit( -1 );
  950.             }
  951.         do {
  952.             if (i < MAXTOK-1)
  953.                 token[i++] = (char)ch;
  954.             ch = getc( fp );
  955.             } while (isdigit( ch ));
  956.         while (ch == ' ' || ch == '\t')
  957.             ch = getc( fp );
  958.         if (ch != ')') {
  959.             FileLine;
  960.             fprintf( stderr,
  961.                 "syntax error: expected right paren\n" );
  962.             exit( -1 );
  963.             }
  964.         if (i < MAXTOK-1)
  965.             token[i++] = (char)ch;
  966.         token[i] = 0;
  967.         return( TOK_ROWCOLUMN );
  968.         }
  969.     else {
  970.         FileLine;
  971.         fprintf( stderr, "syntax error: unrecognized token\n" );
  972.         exit( -1 );
  973.         }
  974.     }
  975.  
  976. static char far *fcopy ( p ) /* return ptr to far string copy */
  977.     char *p;
  978.     {
  979.     char far *q;
  980.     char far *r;
  981.  
  982.     if (!(q = r = _fmalloc( strlen( p ) + 1 )))
  983.         Nomem();
  984.     while (*r++ = *p++) /* copy string */
  985.         ;
  986.     return( q );
  987.     }
  988.  
  989. static int same ( p, q ) /* return 1 if far strings are identical, else 0 */
  990.     char far *p;
  991.     char far *q;
  992.     {
  993.     while (*p && *p == *q) { /* compare bytes until mismatch or end */
  994.         p++;
  995.         q++;
  996.         }
  997.     return( (*p || *q) ? 0 : 1 );
  998.     }
  999.  
  1000. void Report ( fp ) /* output routed board */
  1001.     FILE *fp;
  1002.     {
  1003.     int r, c;
  1004.     char b;
  1005.     long x;
  1006.  
  1007.     printf( "Enter Report()\n" );
  1008.     /* output dimensions first */
  1009.     b = (char)Nrows;    putc( b, fp );
  1010.     b = (char)(Nrows>>8);    putc( b, fp );
  1011.     b = (char)Ncols;    putc( b, fp );
  1012.     b = (char)(Ncols>>8);    putc( b, fp );
  1013.     /* now do rows and columns */
  1014.     for (r = 0; r < Nrows; r++)
  1015.         for (c = 0; c < Ncols; c++) {
  1016.             x = GetCell( r, c, TOP ); /* first do frontside */
  1017.             b = (char)x;        putc( b, fp );
  1018.             b = (char)(x>>8);    putc( b, fp );
  1019.             b = (char)(x>>16);    putc( b, fp );
  1020.             b = (char)(x>>24);    putc( b, fp );
  1021.             x = GetCell( r, c, BOTTOM ); /* then do backside */
  1022.             b = (char)x;        putc( b, fp );
  1023.             b = (char)(x>>8);    putc( b, fp );
  1024.             b = (char)(x>>16);    putc( b, fp );
  1025.             b = (char)(x>>24);    putc( b, fp );
  1026.             }
  1027.     if (ferror( fp ))
  1028.         fprintf( stderr, "output error; disk might be full\n" );
  1029.     printf( "Exit Report()\n" );
  1030.     }
  1031.